#region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU General Public License.
/// </copyright>
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Osh.Dvb
{
	/// <summary>
	/// Implements IPacketStream over a Packetized Elementary Stream (without packet_start_code_prefix) from the source stream.
	/// See ISO/IEC 13818-1 (section 2.4.3.6 PES packet).
	/// </summary>
	public class PesStream : PacketStream
	{
		private static readonly byte[] _prefixBytes = new byte[] { 0, 0, 1 };	// packet_start_code_prefix
		private Stream _sourceStream;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="stream">Source PES stream without packet_start_code_prefix field.</param>
		public PesStream(Stream stream)
		{
			if(stream == null)
				throw new ArgumentNullException("stream");
			_sourceStream = stream;
		}

		protected override bool MoveToNextPacketInternal()
		{
			if(!ReadPacketStartCodePrefix())
				return false;

			int byte3 = _sourceStream.ReadByte(); // stream_id
			if(byte3 == -1)
				return false;

			int byte4 = _sourceStream.ReadByte();
			int byte5 = _sourceStream.ReadByte();

			int packetLength = (byte4 << 8) | byte5;
			this.PacketSize = 3 + 1 + 2 + packetLength;

			EnsurePacketBufferSize(this.PacketSize);

			this.PacketBuffer[0] = _prefixBytes[0];
			this.PacketBuffer[1] = _prefixBytes[1];
			this.PacketBuffer[2] = _prefixBytes[2];
			this.PacketBuffer[3] = (byte)byte3;
			this.PacketBuffer[4] = (byte)byte4;
			this.PacketBuffer[5] = (byte)byte5;

			return Utils.ReadStream(_sourceStream, this.PacketBuffer, 6, packetLength);
		}

		public override void Close()
		{
			base.Close();
			_sourceStream.Close();
		}

		private bool ReadPacketStartCodePrefix()
		{
			int prefixRead = 0;
			while(prefixRead < _prefixBytes.Length)
			{
				int byte0 = _sourceStream.ReadByte();
				if(byte0 == -1)
					return false;

				if(byte0 == _prefixBytes[prefixRead])
					prefixRead++;
				else
					prefixRead = 0;	// not quite right (should try already read bytes), but for buggy stream it's more then enough
			}
			return true;
		}
	}
}
